package dice.sinanya;

import com.forte.qqrobot.exception.BotVerifyException;
import com.forte.qqrobot.exception.EnumInstantiationException;
import com.forte.qqrobot.exception.EnumInstantiationRequireException;
import com.forte.qqrobot.log.LogLevel;
import com.forte.qqrobot.log.QQLog;
import com.forte.qqrobot.sender.MsgSender;
import com.forte.qqrobot.utils.CQCodeUtil;
import com.simbot.component.mirai.MiraiApp;
import com.simbot.component.mirai.MiraiApplication;
import com.simbot.component.mirai.MiraiConfiguration;
import dice.sinanya.db.fire.SelectFire;
import dice.sinanya.db.groupSwitch.SelectGroupSwitch;
import dice.sinanya.db.heap.InsertHeap;
import dice.sinanya.db.properties.ban.SelectBanProperties;
import dice.sinanya.db.properties.game.SelectGameProperties;
import dice.sinanya.db.properties.system.SelectSystemProperties;
import dice.sinanya.db.welcome.SelectWelcome;
import dice.sinanya.dice.system.DevInfo;
import dice.sinanya.exceptions.CantFindQqIdException;
import dice.sinanya.start.MiraiConfig;
import dice.sinanya.start.RunLevel;
import dice.sinanya.start.SavePid;
import dice.sinanya.tools.getinfo.GetLocationPath;
import dice.sinanya.tools.getinfo.GetPath;
import dice.sinanya.tools.getinfo.SystemType;
import dice.sinanya.tools.imal.NewKeywordMatchTypeFactory;
import dice.sinanya.tools.makedata.MakeDiceLog;
import dice.sinanya.windows.Login;
import dice.sinanya.windows.Setting;
import dice.sinanya.windows.SplashWindow;
import net.mamoe.mirai.utils.BotConfiguration;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.core.LoggerContext;

import javax.swing.*;
import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.Locale;
import java.util.regex.Pattern;

import static dice.sinanya.db.redis.FlushRedisAddress.flushRedisAddress;
import static dice.sinanya.db.reply.SelectReply.flushAllReplyFromDatabase;
import static dice.sinanya.db.system.FlushSwitch.flushSwitch;
import static dice.sinanya.db.system.SelectBot.flushBot;
import static dice.sinanya.system.MessagesSystem.loginInfo;
import static dice.sinanya.tools.getinfo.BanList.flushBanList;
import static dice.sinanya.tools.getinfo.CheckSystem.checkSystem;
import static dice.sinanya.tools.getinfo.DefaultMaxRolls.flushMaxRolls;
import static dice.sinanya.tools.getinfo.GetMessagesProperties.*;
import static dice.sinanya.tools.getinfo.History.flushHistory;
import static dice.sinanya.tools.getinfo.Kp.flushKp;
import static dice.sinanya.tools.getinfo.LogTag.flushLogTag;
import static dice.sinanya.tools.getinfo.RoleChoose.flushRoleChoose;
import static dice.sinanya.tools.getinfo.RoleChoose.flushRoleLock;
import static dice.sinanya.tools.getinfo.RoleInfo.flushRoleInfoCache;
import static dice.sinanya.tools.getinfo.Team.flushTeamEn;
import static dice.sinanya.tools.getinfo.WhiteList.flushWhiteGroupList;
import static dice.sinanya.tools.getinfo.WhiteList.flushWhiteUserList;
import static dice.sinanya.tools.makedata.FullWidth2halfWidth.fullWidth2halfWidth;

public class SinaNya implements MiraiApp {
    public static final SystemType systemType = checkSystem();
    private static final Logger logger = LogManager.getRootLogger();
    //private static final Logger logger = LogManager.getLogger(SinaNya.class.getName());
    public static RunLevel runLevel = RunLevel.CQA;
    static SplashWindow splashWindow;


    public static void main(String[] args) throws EnumInstantiationRequireException, EnumInstantiationException {
        MakeDiceLog makeDiceLog = new MakeDiceLog();
        QQLog.setLogBack(((msg, level, e) -> {
            switch (level) {
                case DEBUG:
                    makeDiceLog.makeDiceLog(msg, level);
                    logger.debug(msg, e);
                    break;
                case SUCCESS:
                case INFO:
                    makeDiceLog.makeDiceLog(msg, level);
                    logger.info(msg, e);
                    break;
                case WARNING:
                    makeDiceLog.makeDiceLog(msg, level);
                    logger.warn(msg, e);
                    break;
                case ERROR:
                    makeDiceLog.makeDiceLog(msg, level);
                    logger.error(msg, e);
                    break;
                default:
                    logger.info(msg, e);
            }
            return false;
        }));
        NewKeywordMatchTypeFactory.registerType("SINANYA_REGEX", (msg, regex) -> Pattern.compile(regex.toString(), Pattern.CASE_INSENSITIVE | Pattern.DOTALL).matcher(fullWidth2halfWidth(msg.trim().toLowerCase())).find());
        MiraiApplication application = new MiraiApplication();
        try {
            application.run(new SinaNya(), args);
        } catch (BotVerifyException e) {
            logger.error(e.getMessage(), e);
            splashWindow.setVisible(false);
            JOptionPane.showMessageDialog(null, "登录失败，QQ接口返回账号或密码错误\n" + e.getMessage());
        }
    }

    @Override
    public void before(MiraiConfiguration configuration) {
        MiraiConfig miraiConfig = new MiraiConfig();
        miraiConfig.init();
        miraiConfig.flushLogin();
//        miraiConfig.flushDevice();
//        configuration.getBotConfiguration().setDeviceInfo(new Device());
//        miraiConfig.insertDevice();
        final JFrame runWindows = new JFrame("启动中窗口");
        runWindows.setSize(400, 400);
        runWindows.setLocationRelativeTo(null);
        runWindows.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        File icon = null;
        try {
            icon = miraiConfig.findDir("loading.gif");
        } catch (IOException ioException) {
            ioException.printStackTrace();
            JOptionPane.showMessageDialog(null, "登录失败，找不到图标文件");
            System.exit(-1);
        }
        splashWindow = new SplashWindow(icon.getPath(), runWindows);
        logger.debug(icon.getAbsolutePath());
        splashWindow.setVisible(false);
        final JFrame jf = new JFrame("登陆窗口");
        jf.setSize(400, 400);
        jf.setLocationRelativeTo(null);
        jf.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        new Login(jf).setVisible(true);
        int time = 0;
        while (time <= 8 || loginInfo.isInput() || loginInfo.getPasswd() == null) {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            time++;
            if (!systemType.equals(SystemType.LINUX) && time >= 60) {
                System.exit(-1);
            }
        }
        jf.setVisible(false);
        splashWindow.setVisible(true);
        if (!loginInfo.isInput() && loginInfo.getPasswd() == null) {
            miraiConfig.flushLogin();
        }

//        BotConfiguration conf = new BotConfiguration();
//        conf.setDeviceInfo(c -> new MiraiSystemDeviceInfo(loginInfo.getLoginId(), 1));
//        configuration.setAutoRelogin(true);
        configuration.setDeviceInfoSeed(114514L);
        configuration.setProtocol(BotConfiguration.MiraiProtocol.ANDROID_PHONE);
        configuration.setUseSimbotBotLog(true);
        configuration.setUseSimbotNetworkLog(true);
        configuration.setScannerPackage("dice.sinanya.listener");
        String tmp = String.format("%s:%s", loginInfo.getLoginId(), loginInfo.getPasswd().replace(",", "\\,"));
        configuration.registerBotsFormatter(tmp);
        configuration.setLogLevel(LogLevel.DEBUG);
    }

    @Override
    public void after(CQCodeUtil cqCodeUtil, MsgSender sender) {
        initMessagesSystemProperties();
        flushBot();
        try {
            new DevInfo().initDevInfo();
        } catch (IOException e) {
            e.printStackTrace();
        }
        logger.info(System.getProperty("os.name").toLowerCase(Locale.US));
        String log4jxml2 = null;
        switch (systemType) {
            case LINUX:
            case WIN:
                entitySystemProperties.setSystemDir(new File(URLDecoder.decode(new GetPath().getPath()), "UTF-8").getParentFile().getParentFile().getPath());
                logger.info("当前系统目录为:\t" + entitySystemProperties.getSystemDir("0"));
                log4jxml2 = entitySystemProperties.getSystemDir("0") + "/SinaNya/conf/log4j.properties";
                System.setProperty("log_path", entitySystemProperties.getSystemDir("0") + "/SinaNya/logs/");
                break;
            case MAC:
                try {
                    entitySystemProperties.setSystemDir(new File(URLDecoder.decode(new GetPath().getPath(), "UTF-8")).getParentFile().getPath());
                } catch (UnsupportedEncodingException e) {
                    e.printStackTrace();
                }
                String path;
                String buildClassTargetDir = "/target/classes";
                path = new GetLocationPath().getLocationPath().split(":")[0];
                if (path.contains(buildClassTargetDir)) {
                    path = path.replace(buildClassTargetDir, "");
                }
                log4jxml2 = path + "/src/main/resources/log4j2.xml";
                System.setProperty("LOG_HOME", path + "/logs/");
                break;
            default:
                System.exit(-1);
        }
        LoggerContext logContext = (LoggerContext) org.apache.logging.log4j.LogManager.getContext(false);
        File conFile = null;
        try {
            conFile = new File(URLDecoder.decode(log4jxml2, "UTF-8"));
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        logContext.setConfigLocation(conFile.toURI());
        logContext.reconfigure();

        loginInfo.setLoginId(Long.parseLong(sender.getLoginInfo().getQQ()));
        String name = sender.getLoginInfo().getName();
        loginInfo.setLoginName(name);
        initMessagesBanProperties();
        initMessagesGameProperties();
        new SelectGroupSwitch().flushGroupSwitchFromDataBase();
        new SelectSystemProperties().flushProperties();
        new SelectBanProperties().flushProperties();
        new SelectGameProperties().flushProperties();
        new SelectWelcome().flushProperties();
        new SelectFire().flushFireSwitch();
        logger.info("开始刷写数据库");
        flushTeamEn();
        logger.info("读取幕间成长到缓存");
        flushMaxRolls();
        logger.info("读取最大默认骰到缓存");
        flushRoleChoose();
        logger.info("读取当前已选角色到缓存");
        flushRoleLock();
        logger.info("读取角色锁定情况到缓存");
        flushRoleInfoCache();
        logger.info("读取角色信息到缓存");
        flushLogTag();
        logger.info("读取日志开关到缓存");
        flushKp();
        logger.info("读取kp主群设定到缓存");
        flushHistory();
        logger.info("读取骰点历史信息到缓存");
        flushAllReplyFromDatabase();
        if (entityBanProperties.isCloudBan()) {
            flushBanList();
            logger.info("读取云黑列表到缓存");
        }
        if (entityBanProperties.isWhiteGroup()) {
            flushWhiteGroupList();
        }

        if (entityBanProperties.isWhiteUser()) {
            flushWhiteUserList();
        }
//        if (entityBanProperties.isPrometheus()) {
//            new dice.sinanya.monitor.Prometheus().start();
//            logger.info("开启普罗米修斯监控");
//        }

        flushSwitch();
        try {
            new InsertHeap().updateHeap();
        } catch (CantFindQqIdException e) {
            logger.error(e.getMessage(), e);
        }
        flushRedisAddress();
//        flushZooKeeperList();
//        selectOnlineBotListVersion();
        //打开zookeeper连接
        splashWindow.setVisible(false);
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                logger.info("init setting");
                new Setting().setVisible(true); //这个就是程序界面初始化
//                    try {
//                        new SystemTray().setVisible(true);
//                    } catch (UnsupportedEncodingException e) {
//                        e.printStackTrace();
//                    }
            }
        });
        new SavePid().savePid();
    }
}
